﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Pixysoft.Framework.Verifications;
using Pixysoft.Tools;
using Pixysoft.Weblications.Sango.Formular;

namespace Pixysoft.Weblications.Sango.Battle
{
    /// <summary>
    /// 日后使用memcache代替
    /// </summary>
    class RvrSectionController
    {
        /// <summary>
        /// 已经加入群战的用户列表，防止用户反复加入
        /// USERCODE <> ROOMCODE
        /// </summary>
        Dictionary<string, long> joinedUsers = new Dictionary<string, long>();
        /// <summary>
        /// 群战房间
        /// </summary>
        List<RvrSectionTeam> teams = new List<RvrSectionTeam>();

        private static ReaderWriterLock locker = new ReaderWriterLock();

        private static volatile RvrSectionController instance;

        private static object syncRoot = new Object();

        public static RvrSectionController Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                        {
                            instance = new RvrSectionController();
                        }
                    }
                }
                return instance;
            }
        }

        /// <summary>
        /// 用户是否已经加入了地区战
        /// </summary>
        /// <returns></returns>
        public bool HasJoinSectionTeam(string usercode)
        {
            locker.AcquireReaderLock(Timeout.Infinite);

            try
            {
                return joinedUsers.ContainsKey(usercode);
            }
            finally
            {
                locker.ReleaseReaderLock();
            }
        }

        /// <summary>
        /// 获取地区战参与人员主键
        /// </summary>
        /// <param name="sectionSerialcode"></param>
        /// <param name="targetSectionSerialcode"></param>
        /// <returns></returns>
        public RvrSectionTeam GetSectionTeam(Entities.Sys_Section section, Entities.Sys_Section targetSection)
        {
            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                return UnsafeGetSectionTeam(section, targetSection);
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        /// <summary>
        /// 尝试获取用户加入的地区战信息
        /// 如果没有返回null
        /// </summary>
        /// <param name="usercode"></param>
        /// <returns></returns>
        public RvrSectionTeam TryGetSectionTeam(string usercode)
        {
            locker.AcquireReaderLock(Timeout.Infinite);

            try
            {
                if (!joinedUsers.ContainsKey(usercode))
                    return null;

                long roomcode = joinedUsers[usercode];

                RvrSectionTeam team = this.UnsafeTryGetSectionTeam(roomcode);

                return team;
            }
            finally
            {
                locker.ReleaseReaderLock();
            }
        }

        /// <summary>
        /// 加入地区战
        /// </summary>
        /// <param name="roomcode"></param>
        /// <param name="usercode"></param>
        /// <returns></returns>
        public RvrSectionTeam JoinSectionTeam(long roomcode, string usercode)
        {
            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                if (joinedUsers.ContainsKey(usercode))
                    throw Exceptions.VerificationFailedException(roomcode, usercode);

                RvrSectionTeam team = UnsafeTryGetSectionTeam(roomcode);

                team.Join(usercode);

                joinedUsers.Add(usercode, team.Roomcode);

                return team;
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        /// <summary>
        /// 离开地区战
        /// 如果已经开战，房间不存在，则返回null
        /// </summary>
        /// <param name="usercode"></param>
        /// <returns></returns>
        public RvrSectionTeam TryLeaveSectionTeam(string usercode)
        {
            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                if (!joinedUsers.ContainsKey(usercode))
                    return null;

                long roomcode = joinedUsers[usercode];

                RvrSectionTeam team = UnsafeTryGetSectionTeam(roomcode);

                if (team == null)
                {
                    return null;
                }

                team.Leave(usercode);

                joinedUsers.Remove(usercode);

                return team;
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }

        private RvrSectionTeam UnsafeGetSectionTeam(Entities.Sys_Section section, Entities.Sys_Section targetSection)
        {
            foreach (RvrSectionTeam team in teams)
            {
                if (team.Section.Sectionserialcode != section.Sectionserialcode)
                    continue;

                if (team.TargetSection.Sectionserialcode != targetSection.Sectionserialcode)
                    continue;

                return team;
            }

            long battledate = SectionFormular.GetSectionRvrBattledate();

            RvrSectionTeam newTeam = new RvrSectionTeam(section, targetSection, battledate);

            teams.Add(newTeam);

            return newTeam;
        }

        private RvrSectionTeam UnsafeTryGetSectionTeam(long roomcode)
        {
            foreach (RvrSectionTeam team in teams)
            {
                if (team.Roomcode == roomcode)
                    return team;
            }

            throw Exceptions.VerificationFailedException(roomcode);
        }


        public List<RvrSectionTeam> Dispatch()
        {
            List<RvrSectionTeam> list = new List<RvrSectionTeam>();

            locker.AcquireWriterLock(Timeout.Infinite);

            try
            {
                foreach (RvrSectionTeam team in teams)
                {
                    if (team.Battledate < GlobalTimer.Instance.ToTimeSequence())
                    {
                        list.Add(team);
                    }
                }

                foreach (RvrSectionTeam team in list)
                {
                    teams.Remove(team);

                    foreach (string teamUsercode in team.Profiles)
                    {
                        joinedUsers.Remove(teamUsercode);
                    }
                }

                return list;
            }
            finally
            {
                locker.ReleaseWriterLock();
            }
        }
    }
}
